use std::{collections::BTreeMap, str::FromStr};

use hex_literal::hex;
// Substrate
use sc_chain_spec::{ChainType, Properties};
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_consensus_grandpa::AuthorityId as GrandpaId;
#[allow(unused_imports)]
use sp_core::ecdsa;
use sp_core::{Pair, Public, H160, U256, crypto::UncheckedInto};
use sp_runtime::{
	traits::{IdentifyAccount, Verify},
	Perbill,
};
// Frontier
use frontier_template_runtime::{
	AccountId, Balance, RuntimeGenesisConfig, SS58Prefix, Signature, WASM_BINARY, SessionKeys,
	StakerStatus, DOLLARS, MaxNominations,
};

// babe mode
use sp_core::sr25519;
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
use sp_consensus_babe::AuthorityId as BabeId;
use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId;
use sp_mixnet::types::AuthorityId as MixnetId;

const ENDOWMENT: Balance = 10_000_000 * DOLLARS;
const STASH: Balance = ENDOWMENT / 1000;

fn session_keys(
	grandpa: GrandpaId,
	babe: BabeId,
	im_online: ImOnlineId,
	authority_discovery: AuthorityDiscoveryId,
	mixnet: MixnetId,
	beefy: BeefyId,
) -> SessionKeys {
	SessionKeys { grandpa, babe, im_online, authority_discovery, mixnet, beefy }
}

// The URL for the telemetry server.
// const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";

/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
pub type ChainSpec = sc_service::GenericChainSpec<RuntimeGenesisConfig>;

/// Generate a crypto pair from seed.
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
	TPublic::Pair::from_string(&format!("//{}", seed), None)
		.expect("static values are valid; qed")
		.public()
}

#[allow(dead_code)]
type AccountPublic = <Signature as Verify>::Signer;

/// Generate an account ID from seed.
/// For use with `AccountId32`, `dead_code` if `AccountId20`.
#[allow(dead_code)]
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
where
	AccountPublic: From<<TPublic::Pair as Pair>::Public>,
{
	AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
}

/// Generate an Aura authority key.
pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) {
	(get_from_seed::<AuraId>(s), get_from_seed::<GrandpaId>(s))
}

fn properties() -> Properties {
	let mut properties = Properties::new();
	properties.insert("tokenDecimals".into(), 18.into());
	properties.insert("ss58Format".into(), SS58Prefix::get().into());
	properties
}

const UNITS: Balance = 1_000_000_000_000_000_000;

pub fn development_config(enable_manual_seal: bool) -> ChainSpec {
	ChainSpec::builder(WASM_BINARY.expect("WASM not available"), Default::default())
		.with_name("Development")
		.with_id("dev")
		.with_chain_type(ChainType::Development)
		.with_properties(properties())
		.with_genesis_config_patch(testnet_genesis(
			// Sudo account (Alith)
			AccountId::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac")),
			// Pre-funded accounts
			vec![
				AccountId::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac")), // Alith
				AccountId::from(hex!("3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0")), // Baltathar
				AccountId::from(hex!("798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc")), // Charleth
				AccountId::from(hex!("773539d4Ac0e786233D90A233654ccEE26a613D9")), // Dorothy
				AccountId::from(hex!("Ff64d3F6efE2317EE2807d223a0Bdc4c0c49dfDB")), // Ethan
				AccountId::from(hex!("C0F0f4ab324C46e55D02D0033343B4Be8A55532d")), // Faith
			],
			// Initial PoA authorities
			vec![authority_keys_from_seed("Alice")],
			// Ethereum chain ID
			SS58Prefix::get() as u64,
			enable_manual_seal,
		))
		.build()
}

pub fn local_testnet_config() -> ChainSpec {
	ChainSpec::builder(WASM_BINARY.expect("WASM not available"), Default::default())
		.with_name("Local Testnet")
		.with_id("local_testnet")
		.with_chain_type(ChainType::Local)
		.with_properties(properties())
		.with_genesis_config_patch(testnet_genesis(
			// Sudo account (Alith)
			AccountId::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac")),
			// Pre-funded accounts
			vec![
				AccountId::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac")), // Alith
				AccountId::from(hex!("3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0")), // Baltathar
				AccountId::from(hex!("798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc")), // Charleth
				AccountId::from(hex!("773539d4Ac0e786233D90A233654ccEE26a613D9")), // Dorothy
				AccountId::from(hex!("Ff64d3F6efE2317EE2807d223a0Bdc4c0c49dfDB")), // Ethan
				AccountId::from(hex!("C0F0f4ab324C46e55D02D0033343B4Be8A55532d")), // Faith
			],
			vec![
				authority_keys_from_seed("Alice"),
				authority_keys_from_seed("Bob"),
			],
			42,
			false,
		))
		.build()
}

/// Configure initial storage state for FRAME modules.
fn testnet_genesis(
	sudo_key: AccountId,
	endowed_accounts: Vec<AccountId>,
	initial_authorities: Vec<(AuraId, GrandpaId)>,
	chain_id: u64,
	enable_manual_seal: bool,
) -> serde_json::Value {
	let evm_accounts = {
		let mut map = BTreeMap::new();
		map.insert(
			// H160 address of Alice dev account
			// Derived from SS58 (42 prefix) address
			// SS58: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
			// hex: 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d
			// Using the full hex key, truncating to the first 20 bytes (the first 40 hex chars)
			H160::from_str("d43593c715fdd31c61141abd04a99fd6822c8558")
				.expect("internal H160 is valid; qed"),
			fp_evm::GenesisAccount {
				balance: U256::from_str("0xffffffffffffffffffffffffffffffff")
					.expect("internal U256 is valid; qed"),
				code: Default::default(),
				nonce: Default::default(),
				storage: Default::default(),
			},
		);
		map.insert(
			// H160 address of CI test runner account
			H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b")
				.expect("internal H160 is valid; qed"),
			fp_evm::GenesisAccount {
				balance: U256::from_str("0xffffffffffffffffffffffffffffffff")
					.expect("internal U256 is valid; qed"),
				code: Default::default(),
				nonce: Default::default(),
				storage: Default::default(),
			},
		);
		map.insert(
			// H160 address for benchmark usage
			H160::from_str("1000000000000000000000000000000000000001")
				.expect("internal H160 is valid; qed"),
			fp_evm::GenesisAccount {
				nonce: U256::from(1),
				balance: U256::from(1_000_000_000_000_000_000_000_000u128),
				storage: Default::default(),
				code: vec![0x00],
			},
		);
		map
	};

	serde_json::json!({
		"sudo": { "key": Some(sudo_key) },
		"balances": {
			"balances": endowed_accounts
				.iter()
				.cloned()
				.map(|k| (k, 1_000_000 * UNITS))
				.collect::<Vec<_>>()
		},
		"aura": { "authorities": initial_authorities.iter().map(|x| (x.0.clone())).collect::<Vec<_>>() },
		"grandpa": { "authorities": initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect::<Vec<_>>() },
		"evmChainId": { "chainId": chain_id },
		"evm": { "accounts": evm_accounts },
		"manualSeal": { "enable": enable_manual_seal }
	})
}

fn my_testnet_config_genesis() -> serde_json::Value {
	let (initial_authorities, root_key, endowed_accounts, evm_accounts, chain_id) =
		configure_accounts_for_my_testnet();
		mynet_genesis(initial_authorities, vec![], root_key, Some(endowed_accounts), evm_accounts, chain_id)
}

fn configure_accounts_for_my_testnet() -> (
	Vec<(
		AccountId,
		AccountId,
		GrandpaId,
		BabeId,
		ImOnlineId,
		AuthorityDiscoveryId,
		MixnetId,
		BeefyId,
	)>,
	AccountId,
	Vec<AccountId>,
	BTreeMap<H160, fp_evm::GenesisAccount>,
	u64,
) {
	#[rustfmt::skip]
	// stash, controller, session-key, beefy id
	// generated with secret:
	// for i in 1 2 3 4 ; do for j in stash controller; do subkey inspect "$secret"/fir/$j/$i; done; done
	//
	// and
	//
	// for i in 1 2 3 4 ; do for j in session; do subkey inspect --scheme ed25519 "$secret"//fir//$j//$i; done; done
	//
	// and
	//
	// for i in 1 2 3 4 ; do for j in session; do subkey inspect --scheme ecdsa "$secret"//fir//$j//$i; done; done
	let initial_authorities: Vec<(
		AccountId,
		AccountId,
		GrandpaId,
		BabeId,
		ImOnlineId,
		AuthorityDiscoveryId,
		MixnetId,
		BeefyId,
	)> = vec![
		(
			// 5D77z8cNg14TpDZPptGc3j1naKkoiBjW6BBn2eXPcpsWdVdv
			// array_bytes::hex_n_into_unchecked("2e13f2d95bde970209cb9caaf9c31bbc2480f02eb61cd78d15e954539d2df359"),
			// 5D77z8cNg14TpDZPptGc3j1naKkoiBjW6BBn2eXPcpsWdVdv
			// array_bytes::hex_n_into_unchecked("2e13f2d95bde970209cb9caaf9c31bbc2480f02eb61cd78d15e954539d2df359"),

			AccountId::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac")), // Alith
			AccountId::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac")), // Alith
			// 5F5uLPAr6GerfaCpHU1AdqkhoP94DB5wDuT3phbi932we88V
			array_bytes::hex2array_unchecked("859e956654fb9da6299d9d67a64c3599c7324a357ab5f77188e23c75b60f9da3")
			.unchecked_into(),
			// 5D77z8cNg14TpDZPptGc3j1naKkoiBjW6BBn2eXPcpsWdVdv
			array_bytes::hex2array_unchecked("2e13f2d95bde970209cb9caaf9c31bbc2480f02eb61cd78d15e954539d2df359")
			.unchecked_into(),
			// 5D77z8cNg14TpDZPptGc3j1naKkoiBjW6BBn2eXPcpsWdVdv
			array_bytes::hex2array_unchecked("2e13f2d95bde970209cb9caaf9c31bbc2480f02eb61cd78d15e954539d2df359")
			.unchecked_into(),
			// 5D77z8cNg14TpDZPptGc3j1naKkoiBjW6BBn2eXPcpsWdVdv
			array_bytes::hex2array_unchecked("2e13f2d95bde970209cb9caaf9c31bbc2480f02eb61cd78d15e954539d2df359")
			.unchecked_into(),
			// 5D77z8cNg14TpDZPptGc3j1naKkoiBjW6BBn2eXPcpsWdVdv
			array_bytes::hex2array_unchecked("2e13f2d95bde970209cb9caaf9c31bbc2480f02eb61cd78d15e954539d2df359")
			.unchecked_into(),
			// 5Ckw66vZxPkCi6EfysHGbc1wPsfi7B1zMtfx6XLCVcC1vU2n
			array_bytes::hex2array_unchecked("020cb432f3a8ef18fadcc7ef25f1eceab832ffc4d8601a7c17961acd5fff624eb6")
			.unchecked_into(),
		),
		(
			// 5GVrkYgwvCtqxzAf4zXDv31syT7bopQrxfNxsUmZQiL9wgeH
			// array_bytes::hex_n_into_unchecked("c42002a4d0c0896d22cfa1bb452016c495e0cbc080fc582b9b3bed12ababe076"),
			// 5GVrkYgwvCtqxzAf4zXDv31syT7bopQrxfNxsUmZQiL9wgeH
			// array_bytes::hex_n_into_unchecked("c42002a4d0c0896d22cfa1bb452016c495e0cbc080fc582b9b3bed12ababe076"),

			AccountId::from(hex!("3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0")), // Baltathar
			AccountId::from(hex!("3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0")), // Baltathar
			// 5DjsktAbYT4hudYUUwCrxvKSB4hyWDbS2ztmFvQQtizJDskq
			array_bytes::hex2array_unchecked("4a1c21a4b71288c5b108ee4b2462ebeb595124b2898993a04d6d8be3ea263ccc")
			.unchecked_into(),
			// 5GVrkYgwvCtqxzAf4zXDv31syT7bopQrxfNxsUmZQiL9wgeH
			array_bytes::hex2array_unchecked("c42002a4d0c0896d22cfa1bb452016c495e0cbc080fc582b9b3bed12ababe076")
			.unchecked_into(),
			// 5GVrkYgwvCtqxzAf4zXDv31syT7bopQrxfNxsUmZQiL9wgeH
			array_bytes::hex2array_unchecked("c42002a4d0c0896d22cfa1bb452016c495e0cbc080fc582b9b3bed12ababe076")
			.unchecked_into(),
			// 5GVrkYgwvCtqxzAf4zXDv31syT7bopQrxfNxsUmZQiL9wgeH
			array_bytes::hex2array_unchecked("c42002a4d0c0896d22cfa1bb452016c495e0cbc080fc582b9b3bed12ababe076")
			.unchecked_into(),
			// 5GVrkYgwvCtqxzAf4zXDv31syT7bopQrxfNxsUmZQiL9wgeH
			array_bytes::hex2array_unchecked("c42002a4d0c0896d22cfa1bb452016c495e0cbc080fc582b9b3bed12ababe076")
			.unchecked_into(),
			// 5Cn3fNBRAQT1n6qJrHoVpTU1hvXE8hZsdSbyDsQV4YugiedA
			array_bytes::hex2array_unchecked("0238781637b5bfa32d8408f6ae3e00c617e688e4f9171a5a40831945f861f999e3")
			.unchecked_into(),
		),
		(
			// 5CkGc8P1cG5eu7NDpYYjBnp5tudRKUwBBDZeKGQgn15EAeQ4
			// array_bytes::hex_n_into_unchecked("1e2cd0927cac8078f7e1ec5388b40adda0bd808b03c381f23c1976ef5f4fdf04"),
			// 5CkGc8P1cG5eu7NDpYYjBnp5tudRKUwBBDZeKGQgn15EAeQ4
			// array_bytes::hex_n_into_unchecked("1e2cd0927cac8078f7e1ec5388b40adda0bd808b03c381f23c1976ef5f4fdf04"),

			AccountId::from(hex!("798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc")), // Charleth
			AccountId::from(hex!("798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc")), // Charleth
			// 5HebPKkQfsYhBdkQEuYRqaAQfQsVtHvWxbBt4Yxh1rKMGQAU
			array_bytes::hex2array_unchecked("f705b9e4157ac0819df31dc169a82bf50d5717c0b5af21b778e9491cd96e3d11")
			.unchecked_into(),
			// 5CkGc8P1cG5eu7NDpYYjBnp5tudRKUwBBDZeKGQgn15EAeQ4
			array_bytes::hex2array_unchecked("1e2cd0927cac8078f7e1ec5388b40adda0bd808b03c381f23c1976ef5f4fdf04")
			.unchecked_into(),
			// 5CkGc8P1cG5eu7NDpYYjBnp5tudRKUwBBDZeKGQgn15EAeQ4
			array_bytes::hex2array_unchecked("1e2cd0927cac8078f7e1ec5388b40adda0bd808b03c381f23c1976ef5f4fdf04")
			.unchecked_into(),
			// 5CkGc8P1cG5eu7NDpYYjBnp5tudRKUwBBDZeKGQgn15EAeQ4
			array_bytes::hex2array_unchecked("1e2cd0927cac8078f7e1ec5388b40adda0bd808b03c381f23c1976ef5f4fdf04")
			.unchecked_into(),
			// 5CkGc8P1cG5eu7NDpYYjBnp5tudRKUwBBDZeKGQgn15EAeQ4
			array_bytes::hex2array_unchecked("1e2cd0927cac8078f7e1ec5388b40adda0bd808b03c381f23c1976ef5f4fdf04")
			.unchecked_into(),
			// 5DoUf7ALcMobZ95A2kwJWmqGT3rr9M3DNYDioBNJq2P8psuD
			array_bytes::hex2array_unchecked("0285b9f68349ed3f34f6d5abcc225c7f708e77a8030f3a61adef65db4d4d9c19ff")
			.unchecked_into(),
		),
		(
			// 5CamZgrcemJbtQGmAtWNYoePwkijcxXo6NtHAGZiHDuPSkXb
			// array_bytes::hex_n_into_unchecked("16edd77e6e919c563848bea2b64069feebb538fea7448d52a8481b8641d0a37a"),
			// 5CamZgrcemJbtQGmAtWNYoePwkijcxXo6NtHAGZiHDuPSkXb
			// array_bytes::hex_n_into_unchecked("16edd77e6e919c563848bea2b64069feebb538fea7448d52a8481b8641d0a37a"),

			AccountId::from(hex!("773539d4Ac0e786233D90A233654ccEE26a613D9")), // Dorothy
			AccountId::from(hex!("773539d4Ac0e786233D90A233654ccEE26a613D9")), // Dorothy
			// 5EyfVRJ4muFmaHSFG2dyAoAg19BCteTN8Yas3f9USwrh6cyL
			array_bytes::hex2array_unchecked("80dc81e821e59c9436d5c869dd45eb449fe053c6d4e7bebb2c561c9b867eb87c")
			.unchecked_into(),
			// 5CamZgrcemJbtQGmAtWNYoePwkijcxXo6NtHAGZiHDuPSkXb
			array_bytes::hex2array_unchecked("16edd77e6e919c563848bea2b64069feebb538fea7448d52a8481b8641d0a37a")
			.unchecked_into(),
			// 5CamZgrcemJbtQGmAtWNYoePwkijcxXo6NtHAGZiHDuPSkXb
			array_bytes::hex2array_unchecked("16edd77e6e919c563848bea2b64069feebb538fea7448d52a8481b8641d0a37a")
			.unchecked_into(),
			// 5CamZgrcemJbtQGmAtWNYoePwkijcxXo6NtHAGZiHDuPSkXb
			array_bytes::hex2array_unchecked("16edd77e6e919c563848bea2b64069feebb538fea7448d52a8481b8641d0a37a")
			.unchecked_into(),
			// 5CamZgrcemJbtQGmAtWNYoePwkijcxXo6NtHAGZiHDuPSkXb
			array_bytes::hex2array_unchecked("16edd77e6e919c563848bea2b64069feebb538fea7448d52a8481b8641d0a37a")
			.unchecked_into(),
			// 5DNvwqBxNbZtHwKf4r9UmiEin7bgHN3DqUsEKseGZ3x5Pzh1
			array_bytes::hex2array_unchecked("02c64816eea9ed87f899d8c117b03c86a8add2ecd6d13481b48f61c21a10209df8")
			.unchecked_into(),
		),
	];

	let endowed_accounts = vec![
		AccountId::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac")), // Alith
		AccountId::from(hex!("3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0")), // Baltathar
		AccountId::from(hex!("798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc")), // Charleth
		AccountId::from(hex!("773539d4Ac0e786233D90A233654ccEE26a613D9")), // Dorothy
		AccountId::from(hex!("Ff64d3F6efE2317EE2807d223a0Bdc4c0c49dfDB")), // Ethan
		AccountId::from(hex!("C0F0f4ab324C46e55D02D0033343B4Be8A55532d")), // Faith
	];

	// generated with secret: subkey inspect "$secret"/fir
	// let root_key: AccountId = array_bytes::hex_n_into_unchecked(
	// 	// 5Ff3iXP75ruzroPWRP2FYBHWnmGGBSb63857BgnzCoXNxfPo
	// 	"9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809",
	// );
	let root_key: AccountId = AccountId::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"));

	let endowed_accounts: Vec<AccountId> = vec![root_key.clone()];

	let evm_accounts = {
		let mut map = BTreeMap::new();
		map.insert(
			// H160 address of Alice dev account
			// Derived from SS58 (42 prefix) address
			// SS58: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
			// hex: 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d
			// Using the full hex key, truncating to the first 20 bytes (the first 40 hex chars)
			H160::from_str("d43593c715fdd31c61141abd04a99fd6822c8558")
				.expect("internal H160 is valid; qed"),
			fp_evm::GenesisAccount {
				balance: U256::from_str("0xffffffffffffffffffffffffffffffff")
					.expect("internal U256 is valid; qed"),
				code: Default::default(),
				nonce: Default::default(),
				storage: Default::default(),
			},
		);
		map.insert(
			// H160 address of CI test runner account
			H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b")
				.expect("internal H160 is valid; qed"),
			fp_evm::GenesisAccount {
				balance: U256::from_str("0xffffffffffffffffffffffffffffffff")
					.expect("internal U256 is valid; qed"),
				code: Default::default(),
				nonce: Default::default(),
				storage: Default::default(),
			},
		);
		map.insert(
			// H160 address for benchmark usage
			H160::from_str("1000000000000000000000000000000000000001")
				.expect("internal H160 is valid; qed"),
			fp_evm::GenesisAccount {
				nonce: U256::from(1),
				balance: U256::from(1_000_000_000_000_000_000_000_000u128),
				storage: Default::default(),
				code: vec![0x00],
			},
		);
		map
	}; 

	let chain_id = 42;

	(initial_authorities, root_key, endowed_accounts, evm_accounts, chain_id)
}

pub fn local_mynet_config() -> ChainSpec {
	ChainSpec::builder(WASM_BINARY.expect("WASM not available"), Default::default())
		.with_name("My Testnet")
		.with_id("my_testnet")
		.with_chain_type(ChainType::Live)
		.with_properties(properties())
		.with_genesis_config_patch(my_testnet_config_genesis())
		.build()
}
/// Helper function to create RuntimeGenesisConfig json patch for testing.
pub fn mynet_genesis(
	initial_authorities: Vec<(
		AccountId,
		AccountId,
		GrandpaId,
		BabeId,
		ImOnlineId,
		AuthorityDiscoveryId,
		MixnetId,
		BeefyId,
	)>,
	initial_nominators: Vec<AccountId>,
	root_key: AccountId,
	endowed_accounts: Option<Vec<AccountId>>,
	evm_accounts: BTreeMap<H160, fp_evm::GenesisAccount>,
	chain_id: u64,
) -> serde_json::Value {
	let (initial_authorities, endowed_accounts, num_endowed_accounts, stakers) =
		configure_accounts(initial_authorities, initial_nominators, endowed_accounts, STASH);

	serde_json::json!({
		"balances": {
			"balances": endowed_accounts.iter().cloned().map(|x| (x, ENDOWMENT)).collect::<Vec<_>>(),
		},
		"session": {
			"keys": initial_authorities
				.iter()
				.map(|x| {
					(
						x.0.clone(),
						x.0.clone(),
						session_keys(
							x.2.clone(),
							x.3.clone(),
							x.4.clone(),
							x.5.clone(),
							x.6.clone(),
							x.7.clone(),
						),
					)
				})
				.collect::<Vec<_>>(),
		},
		"staking": {
			"validatorCount": initial_authorities.len() as u32,
			"minimumValidatorCount": initial_authorities.len() as u32,
			"invulnerables": initial_authorities.iter().map(|x| x.0.clone()).collect::<Vec<_>>(),
			"slashRewardFraction": Perbill::from_percent(10),
			"stakers": stakers.clone(),
		},
		// "elections": {
		// 	"members": endowed_accounts
		// 		.iter()
		// 		.take((num_endowed_accounts + 1) / 2)
		// 		.cloned()
		// 		.map(|member| (member, STASH))
		// 		.collect::<Vec<_>>(),
		// },
		// "technicalCommittee": {
		// 	"members": endowed_accounts
		// 		.iter()
		// 		.take((num_endowed_accounts + 1) / 2)
		// 		.cloned()
		// 		.collect::<Vec<_>>(),
		// },
		"sudo": { "key": Some(root_key.clone()) },
		"babe": {
			"epochConfig": Some(frontier_template_runtime::BABE_GENESIS_EPOCH_CONFIG),
		},
		// "society": { "pot": 0 },
		// "assets": {
		// 	// This asset is used by the NIS pallet as counterpart currency.
		// 	"assets": vec![(9, get_account_id_from_seed::<sr25519::Public>("Alice"), true, 1)],
		// },
		"nominationPools": {
			"minCreateBond": 10 * DOLLARS,
			"minJoinBond": 1 * DOLLARS,
		},
		"evmChainId": { "chainId": chain_id },
		"evm": { "accounts": evm_accounts },
	})
}

fn configure_accounts(
	initial_authorities: Vec<(
		AccountId,
		AccountId,
		GrandpaId,
		BabeId,
		ImOnlineId,
		AuthorityDiscoveryId,
		MixnetId,
		BeefyId,
	)>,
	initial_nominators: Vec<AccountId>,
	endowed_accounts: Option<Vec<AccountId>>,
	stash: Balance,
) -> (
	Vec<(
		AccountId,
		AccountId,
		GrandpaId,
		BabeId,
		ImOnlineId,
		AuthorityDiscoveryId,
		MixnetId,
		BeefyId,
	)>,
	Vec<AccountId>,
	usize,
	Vec<(AccountId, AccountId, Balance, StakerStatus<AccountId>)>,
) {
	let mut endowed_accounts: Vec<AccountId> = endowed_accounts.unwrap_or_else(|| {
		vec![
			AccountId::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac")), // Alith
			AccountId::from(hex!("3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0")), // Baltathar
			AccountId::from(hex!("798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc")), // Charleth
			AccountId::from(hex!("773539d4Ac0e786233D90A233654ccEE26a613D9")), // Dorothy
			AccountId::from(hex!("Ff64d3F6efE2317EE2807d223a0Bdc4c0c49dfDB")), // Ethan
			AccountId::from(hex!("C0F0f4ab324C46e55D02D0033343B4Be8A55532d")), // Faith
		]
	});
	// endow all authorities and nominators.
	initial_authorities
		.iter()
		.map(|x| &x.0)
		.chain(initial_nominators.iter())
		.for_each(|x| {
			if !endowed_accounts.contains(x) {
				endowed_accounts.push(x.clone())
			}
		});

	// stakers: all validators and nominators.
	let mut rng = rand::thread_rng();
	let stakers = initial_authorities
		.iter()
		.map(|x| (x.0.clone(), x.0.clone(), stash, StakerStatus::Validator))
		.chain(initial_nominators.iter().map(|x| {
			use rand::{seq::SliceRandom, Rng};
			let limit = (MaxNominations::get() as usize).min(initial_authorities.len());
			let count = rng.gen::<usize>() % limit;
			let nominations = initial_authorities
				.as_slice()
				.choose_multiple(&mut rng, count)
				.into_iter()
				.map(|choice| choice.0.clone())
				.collect::<Vec<_>>();
			(x.clone(), x.clone(), stash, StakerStatus::Nominator(nominations))
		}))
		.collect::<Vec<_>>();

	let num_endowed_accounts = endowed_accounts.len();

	(initial_authorities, endowed_accounts, num_endowed_accounts, stakers)
}
